package org.annoflow.javassist;

import java.util.List;

import javassist.CannotCompileException;
import javassist.CtClass;


/**
 * The Class AbstractCommand. This class represents the most basic functions of
 * a command as interpreted by a javassist configuration file.
 */
public abstract class AbstractCommand implements CommandInterface
{
	/**
	 * The Class CommandNotImplementedException. This exception results from a
	 * command that requires operations not implemented by javassist.
	 */
	public class CommandNotImplementedException extends MalformedCommandException
	{

		/** The Constant serialVersionUID. */
		private static final long serialVersionUID = 1L;

		/**
		 * Instantiates a new command not implemented exception.
		 * 
		 * @param command
		 *            the command
		 */
		public CommandNotImplementedException(CommandInterface command)
		{
			super(
					"The combination of Translation Type and Signature Type is not supported:  "
							+ command.toString());
		}

	}
	
	/**
	 * The Class MalformedCommandArgumentException. This exception results from a
	 * command argument that is not properly formated in a javassist config file.
	 */
	public class MalformedCommandArgumentException extends
			MalformedCommandException
	{

		/** The Constant serialVersionUID. */
		private static final long serialVersionUID = 1L;

		/**
		 * Instantiates a new malformed command argument exception.
		 * 
		 * @param argList
		 *            the arg list
		 */
		public MalformedCommandArgumentException(List<String> argList)
		{
			super("The arguments parsed are not in the correct format:  "
					+ argList.toString());
		}

	}

	

	/**
	 * The Enum SignatureType. The type of signature to translate.
	 */
	public enum SignatureType
	{
		CONSTRUCTORCALL,
		NEWEXPR,
		METHODCALL,
		STATICDEFINITION,
		NEWARRAY,
		FIELDACCESS,
		INSTANCEOF,
		CAST,
		HANDLER,
		METHODBODY
	};

	/** The sig type. */
	SignatureType sigType;

	/** The un parsed args. */
	List<String> unParsedArgs;

	/** The trans type. */
	//TranslationType transType;

	/** The command. */
	String command;

	/** The signature. */
	String signature;

	/**
	 * Instantiates a new abstract command using a list of arguments parsed from
	 * a configuration file.
	 * 
	 * @param argList
	 *            the arguments parsed from a javassist config file
	 * 
	 * @throws MalformedCommandException
	 *             the malformed command exception
	 */
	protected AbstractCommand(List<String> argList)
			throws MalformedCommandException
	{
		unParsedArgs = argList;
		sigType = findSignatureType();
		//transType = findTranslationType();
		signature = findSignature();
		command = findReplacement();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cloudspace.vm.javassist.commands.CommandInterface#getSignatureType
	 * ()
	 */
	public SignatureType getSignatureType()
	{
		return sigType;
	}

	public String getReplacement()
	{
		return command;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * cloudspace.vm.javassist.commands.CommandInterface#getSignature
	 * ()
	 */
	public String getSignature()
	{
		return signature;
	}
	public String getShortSignature()
	{
		int firstParen = signature.indexOf('(');
		int lastPackageSep = signature.substring(0, firstParen).lastIndexOf('.');
		
		return signature.substring(lastPackageSep+1);
	}
	// List<String> unParsedArgs;
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString()
	{
		return unParsedArgs.toString();
	}


	/**
	 * a utility method for finding replacement text
	 * 
	 * @return the replacement text
	 * 
	 * @throws MalformedCommandArgumentException
	 *             the malformed command argument exception
	 */
	private String findReplacement() throws MalformedCommandArgumentException
	{

		String rep;
		try
		{
			String replText = unParsedArgs.get(3).trim();
			rep = replText.substring(1, unParsedArgs.get(3).length() - 1);
		}
		catch (IndexOutOfBoundsException ex)
		{
			throw new MalformedCommandArgumentException(unParsedArgs);
		}
		//rep =
		rep = rep.trim();
		return rep;
	}
	/*public String getDynamicReplacement()
	{
		//return "if($0 != null && !cloudspace.vm.javassist.ClassAnalyzer.rewriteNeeded($0.getClass(),\""+ getShortSignature() + "\")){ $_=$proceed($$);}else{" + getReplacement()+ "}";
		return command;
	}*/

	/**
	 * A utility method for finding the signature.
	 * 
	 * @return the string
	 * 
	 * @throws MalformedCommandArgumentException
	 *             the malformed command argument exception
	 */
	private String findSignature() throws MalformedCommandArgumentException
	{

		String sig;
		try
		{
			sig = unParsedArgs.get(2);
		}
		catch (IndexOutOfBoundsException ex)
		{
			throw new MalformedCommandArgumentException(unParsedArgs);
		}
		return sig;
	}

	/**
	 * a utility method for finding the type of signature.
	 * 
	 * @return the signature type
	 * 
	 * @throws MalformedCommandArgumentException
	 *             the malformed command argument exception
	 * @throws MalformedSignatureTypeException
	 *             the malformed signature type exception
	 */
	private SignatureType findSignatureType()
			throws MalformedCommandException
	{
		String commandType;
		try
		{
			commandType = unParsedArgs.get(1);
		}
		catch (IndexOutOfBoundsException ex)
		{
			throw new MalformedCommandArgumentException(unParsedArgs);
		}
		if (commandType.equals("ConstructorCall"))
		{
			return SignatureType.CONSTRUCTORCALL;
		}
		else if (commandType.equals("NewExpr"))
		{
			return SignatureType.NEWEXPR;
		}
		else if (commandType.equals("MethodCall"))
		{
			return SignatureType.METHODCALL;
		}
		else if (commandType.equals("StaticDefinition"))
		{
			return SignatureType.STATICDEFINITION;
		}
		else if (commandType.equals("Handler"))
		{
			return SignatureType.HANDLER;
		}
		else if (commandType.equals("Cast"))
		{
			return SignatureType.CAST;
		}
		else if (commandType.equals("InstanceOf"))
		{
			return SignatureType.INSTANCEOF;
		}
		else if (commandType.equals("FieldAccess"))
		{
			return SignatureType.FIELDACCESS;
		}
		else if (commandType.equals("NewArray"))
		{
			return SignatureType.NEWARRAY;
		}
		else if (commandType.equals("MethodBody"))
		{
			return SignatureType.METHODBODY;
		}

		throw new MalformedCommandException("The signature type " + commandType + " is unknown in command:  "
				+ unParsedArgs.toString());
	}
	@Override
	public void translate(CtClass clazz) throws MalformedCommandException, CannotCompileException
	{
		throw new CommandNotImplementedException(this);
	}

}
